/*
 * Copyright (c) 2001, 2004, Oracle and/or its affiliates. All rights reserved.
 * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 */

package com.sun.corba.se.impl.oa.toa;

import org.omg.CORBA.Policy;
import org.omg.PortableInterceptor.ObjectReferenceTemplate;
import org.omg.PortableInterceptor.ObjectReferenceFactory;
import org.omg.PortableInterceptor.ACTIVE;
import org.omg.PortableServer.ServantLocatorPackage.CookieHolder;

import com.sun.corba.se.pept.protocol.ClientDelegate;

import com.sun.corba.se.spi.copyobject.CopierManager;
import com.sun.corba.se.spi.copyobject.ObjectCopier;
import com.sun.corba.se.spi.copyobject.ObjectCopierFactory;
import com.sun.corba.se.spi.ior.ObjectKeyTemplate;
import com.sun.corba.se.spi.ior.iiop.IIOPAddress;
import com.sun.corba.se.spi.ior.iiop.IIOPFactories;
import com.sun.corba.se.spi.oa.OAInvocationInfo;
import com.sun.corba.se.spi.oa.OADestroyed;
import com.sun.corba.se.spi.oa.ObjectAdapterBase;
import com.sun.corba.se.spi.orb.ORB;
import com.sun.corba.se.spi.presentation.rmi.StubAdapter;
import com.sun.corba.se.spi.protocol.RequestDispatcherRegistry;
import com.sun.corba.se.spi.protocol.LocalClientRequestDispatcher;
import com.sun.corba.se.spi.transport.CorbaContactInfoList;

import com.sun.corba.se.impl.ior.JIDLObjectKeyTemplate;
import com.sun.corba.se.impl.oa.NullServantImpl;
import com.sun.corba.se.impl.oa.poa.Policies;
import com.sun.corba.se.impl.oa.toa.TransientObjectManager;
import com.sun.corba.se.impl.orbutil.ORBConstants;
import com.sun.corba.se.impl.protocol.JIDLLocalCRDImpl;

/** The Transient Object Adapter (TOA) represents the OA for purely transient
* objects.  It is used for standard RMI-IIOP as well as backwards compatible
* server support (i.e. the ORB.connect() method)
* Its characteristics include:
* <UL>
* <LI>There is only one OA instance of the TOA.  Its OAId is { "TOA" }</LI>
* <LI>There is not adapter manager.  The TOA manager ID is fixed.<LI>
* <LI>State is the same as ORB state (TBD)</LI>
* </UL>
* Other requirements:
* <UL>
* <LI>All object adapters must invoke ORB.adapterCreated when they are created.
* </LI>
* <LI>All adapter managers must invoke ORB.adapterManagerStateChanged when
* their state changes, mapping the internal state to an ORT state.</LI>
* <LI>AdapterStateChanged must be invoked (from somewhere) whenever
* an adapter state changes that is not due to an adapter manager state change.</LI>
* </UL>
*/
public class TOAImpl extends ObjectAdapterBase implements TOA {
    private TransientObjectManager servants;

    public TOAImpl(ORB orb, TransientObjectManager tom, String codebase) {
        super(orb);
        servants = tom;

        // Make the object key template
        int serverid = ((ORB) getORB()).getTransientServerId();
        int scid = ORBConstants.TOA_SCID;

        ObjectKeyTemplate oktemp = new JIDLObjectKeyTemplate(orb, scid, serverid);

        // REVISIT - POA specific
        Policies policies = Policies.defaultPolicies;

        // REVISIT - absorb codebase into a policy
        initializeTemplate(oktemp, true, policies, codebase, null, // manager id
        oktemp.getObjectAdapterId());
    }

    // Methods required for dispatching requests

    public ObjectCopierFactory getObjectCopierFactory() {
        CopierManager cm = getORB().getCopierManager();
        return cm.getDefaultObjectCopierFactory();
    }

    public org.omg.CORBA.Object getLocalServant(byte[] objectId) {
        return (org.omg.CORBA.Object) (servants.lookupServant(objectId));
    }

    /** Get the servant for the request given by the parameters.
    * This will update thread Current, so that subsequent calls to
    * returnServant and removeCurrent from the same thread are for the
    * same request.
    * @param request is the request containing the rest of the request
    */
    public void getInvocationServant(OAInvocationInfo info) {
        java.lang.Object servant = servants.lookupServant(info.id());
        if (servant == null)
            // This is expected to result in an RMI-IIOP NoSuchObjectException.
            // See bug 4973160.
            servant = new NullServantImpl(lifecycleWrapper().nullServant());
        info.setServant(servant);
    }

    public void returnServant() {
        // NO-OP
    }

    /** Return the most derived interface for the given servant and objectId.
    */
    public String[] getInterfaces(Object servant, byte[] objectId) {
        return StubAdapter.getTypeIds(servant);
    }

    // XXX For now, this does nothing.
    // This will need fixing once we support ORB and thread level policies,
    // but for now, there is no way to associate policies with the TOA, so
    // getEffectivePolicy must always return null.
    public Policy getEffectivePolicy(int type) {
        return null;
    }

    public int getManagerId() {
        return -1;
    }

    public short getState() {
        return ACTIVE.value;
    }

    public void enter() throws OADestroyed {
    }

    public void exit() {
    }

    // Methods unique to the TOA

    public void connect(org.omg.CORBA.Object objref) {
        // Store the objref and get a userkey allocated by the transient
        // object manager.
        byte[] key = servants.storeServant(objref, null);

        // Find out the repository ID for this objref.
        String id = StubAdapter.getTypeIds(objref)[0];

        // Create the new objref
        ObjectReferenceFactory orf = getCurrentFactory();
        org.omg.CORBA.Object obj = orf.make_object(id, key);

        // Copy the delegate from the new objref to the argument
        // XXX handle the case of an attempt to connect a local object.

        org.omg.CORBA.portable.Delegate delegate = StubAdapter.getDelegate(obj);
        CorbaContactInfoList ccil = (CorbaContactInfoList) ((ClientDelegate) delegate).getContactInfoList();
        LocalClientRequestDispatcher lcs = ccil.getLocalClientRequestDispatcher();

        if (lcs instanceof JIDLLocalCRDImpl) {
            JIDLLocalCRDImpl jlcs = (JIDLLocalCRDImpl) lcs;
            jlcs.setServant(objref);
        } else {
            throw new RuntimeException("TOAImpl.connect can not be called on " + lcs);
        }

        StubAdapter.setDelegate(objref, delegate);
    }

    public void disconnect(org.omg.CORBA.Object objref) {
        // Get the delegate, then ior, then transientKey, then delete servant
        org.omg.CORBA.portable.Delegate del = StubAdapter.getDelegate(objref);
        CorbaContactInfoList ccil = (CorbaContactInfoList) ((ClientDelegate) del).getContactInfoList();
        LocalClientRequestDispatcher lcs = ccil.getLocalClientRequestDispatcher();

        if (lcs instanceof JIDLLocalCRDImpl) {
            JIDLLocalCRDImpl jlcs = (JIDLLocalCRDImpl) lcs;
            byte[] oid = jlcs.getObjectId();
            servants.deleteServant(oid);
            jlcs.unexport();
        } else {
            throw new RuntimeException("TOAImpl.disconnect can not be called on " + lcs);
        }
    }
}
